<?php
/**
 * Класс обеспечивает соединение с базой данных
 * Автоматически формирует массивы 
 * Обеспечивает обработку исключительных ситуаций при осуществлении запросов
 * 
 * @author Дмитрий Кузьма <kouzma.d@gmail.com>
 * @version 1.0
 */

class Service_Database {
  private $hConn;   //Дескриптор соединения с базой данных
  /**
   * Конструктор - устанавливаем соединение с БД.
   *
   */
  private function __construct() {

    $hostName  = DB_HOST . ":" . DB_PORT;

    $this->hConn = @mysql_connect($hostName, DB_USER, DB_PASSWORD);
    if(! is_resource($this->hConn)) {
      throw new Exception("Невозможно соединиться с базой данных " .
                         "Хост: \"$hostName\"; Пользователь: \"". DB_USER. "\"", E_USER_ERROR);
    }
    $curBD = @mysql_select_db(DB_NAME);//Выбираем базу данных для работы
    if(! ($curBD)) {
      throw new Exception("Невозможно выбрать базу данных " .
                          "База данных: \"" . DB_NAME . "\"", E_USER_ERROR);
    }
    @mysql_query("SET NAMES 'utf8'");
  }
  
  /**
   * Функция обеспечивает работу шаблона Singleton. Благодаря ей у нас всегда будет только одно подключение к базе
   *
   * @return resource
   */
  static public function instance(){
    static $objDb;
    if(!isset($objDb)){
      $objDb = new Service_Database();
    }
    return $objDb;
  }
  
  /**
   * Получает информацию о последнем вставленном идентификаторе
   *
   * @return integer - значение последнего вставленно идентификатора (false, если не было удачного запроса; 0 если в таблице нет autoincrement)
   */
  public function getLastInsertId(){
    $stmt = "SELECT LAST_INSERT_ID() AS LID";
    $hRes = mysql_query($stmt, $this->hConn);
    if(! $hRes) {//Проверяем, корректно ливыполнен запрос
      $err = mysql_error($this->hConn) . $stmt;
      throw new Exception($err);
    }
    $arrLID = mysql_fetch_assoc($hRes);
    return $arrLID['LID'];      
  }
  /**
   * Вставляет в определенную таблицу массив значений
   *
   * @param string $table - название таблицы
   * @param array $arFieldValues - массив вставляемых значений (ключ соответствует полю в БД)
   * @return integer - количество вставленных строк
   */
  public function insert($table, $arFieldValues) {
    $fields = array_keys($arFieldValues);     //Массив названий элементов таблицы
    $values = array_values($arFieldValues);   //Массив значений

    $escVals = array();   //Выходной массив значений
    foreach($values as $val) {  //Проходим массив значений поэлементно
      if(! is_numeric($val)) {  //Если текущее значение - не число
        $val = "'" . mysql_escape_string($val) . "'";//Приводим к корректному выводу
      }
      $escVals[] = $val;  //Записываем корректное значение в массив
    }
    //Генерируем SQL запрос
    $sql = " INSERT INTO `". $table . "` ( ";
    $sql .= join(", ", $fields);
    $sql .= ' ) VALUES( ';
    $sql .= join(', ', $escVals);
    $sql .= ' )';
    $hRes = @mysql_query($sql, $this->hConn) or die ("Невозможно выполнить запрос" . $sql . $this->hConn);
    if(! $hRes) {  //Если не получен положительный результат о вставке
      $err = mysql_error($this->hConn) . "\n" . $sql;
      throw new Exception($err);
    }
    return mysql_affected_rows($this->hConn);
  }
  
  /**
   * Вставляет в определенную таблицу массив значений
   *
   * @param string $table - название таблицы
   * @param array $arFieldValues - массив вставляемых значений (ключ соответствует полю в БД)
   * @return integer - идентификатор вставленого элемента
   */
  public function insertAutoincrement($table, $arFieldValues) {
    if( $this->insert($table, $arFieldValues) )
      return $this->getLastInsertId();
    else
      return false;      
  }
/**
   * Выполняет запрос на вставку значений
   *
   * @param string $sql - строка запроса
   * @return integer - идентификатор
   */
  public function queryInsertAutoincrement($sql) {
    if( $this->query($sql) > 0)
      return $this->getLastInsertId();
    else
      return false;      
  }  

  /**
   * Удаляет из таблицы все элементы, удовлетворяющие условию
   *
   * @param string $table - название таблицы
   * @param array $arConditions - массив условий (ключ соответствует полю в БД)
   * @return integer - количество удаленных строк
   */
  function delete($table, $arConditions) {

    //Создаем строку WHERE
    $arWhere = array();//Массив элементов для WHERE
    foreach($arConditions as $field => $val) {  //Проходим массив значений поэлементно
      if(! is_numeric($val)) {  //Если текущее значение - не число
        $val = "'" . mysql_escape_string($val) . "'";//Приводим к корректному выводу
      }

      $arWhere[] = "$field = $val";//Записываем корректное значение в массив
    }
    //Формируем запрос на удаление
    $sql = "DELETE FROM $table WHERE " . join(' AND ', $arWhere);

    $hRes = @mysql_query($sql, $this->hConn) or die ("Невозможно выполнить запрос на удаление" . $sql . $this->hConn);
    if(! $hRes) {  //Если не получен положительный результат о вставке
      $err = mysql_error($this->hConn) . $sql;
      throw new Exception($err);
    }

    return mysql_affected_rows($this->hConn);
  }

  /**
   * выполняет любой запрос SQL типа SELECT
   *
   * @param string $sql - строка запроса
   * @return array - двумерный ассоциативный массив
   */
  public function select($sql) {
    $hRes = @mysql_query($sql, $this->hConn);
    if(! $hRes) {//Проверяем, корректно ливыполнен запрос
      $err = mysql_error($this->hConn) . $sql;
      throw new Exception($err);
    }
    $arReturn = array();//Массив для возвращения функцией (результат)
    while( ($row = mysql_fetch_assoc($hRes)) ) {
      $arReturn[] = $row;
    }
    return $arReturn;
  }

  /**
   * выполняет любой запрос SQL типа SELECT для получения информации об одном поле и возвращает простой одномерный массив
   *
   * @param string $sql - строка запроса
   * @return array - одномерный индексный массив
   */
  public function selectSimpleArray($sql) {
    $hRes = @mysql_query($sql, $this->hConn);

    if(! $hRes) {//Проверяем, корректно ливыполнен запрос
      $err = mysql_error($this->hConn) . $sql;
      throw new Exception($err);
    }
    if( mysql_num_rows($hRes) == 0 )
      return NULL;
    $arReturn = array();//Массив для возвращения функцией (результат)
    while( ($row = mysql_fetch_array($hRes)) ) {
      $arReturn[] = $row[0];
    }
    return $arReturn;
  }
  /**
   * выполняет любой запрос SQL типа SELECT для получения информации об одном поле одной строки
   *
   * @param string $sql - строка запроса
   * @return mixed - значение единственного поля
   */
  
  public function selectSimpleField($sql) {
    $hRes = @mysql_query($sql, $this->hConn);

    if(! $hRes) {//Проверяем, корректно ливыполнен запрос
      $err = mysql_error($this->hConn) . $sql;
      throw new Exception($err);
    }
    if( mysql_num_rows($hRes) == 0 )
      return NULL;
    $arTemp =  mysql_fetch_array($hRes);
    return $arTemp[0];
  }    
  
  /**
   * выполняет любой запрос SQL типа SELECT, возвращает только первый элемент 
   *
   * @param string $sql - строка запроса
   * @return array - двумерный ассоциативный массив
   */
  public function selectOne($sql) {
    $hRes = @mysql_query($sql, $this->hConn);
    if(! $hRes) {//Проверяем, корректно ливыполнен запрос
      $err = mysql_error($this->hConn) . $sql;
      throw new Exception($err);
    }
    if( mysql_num_rows($hRes) == 0 )
      return NULL;
    return mysql_fetch_assoc($hRes);
  }

  /**
   * Выполняет произвольный SQL запрос
   *
   * @param string $sql - строка запроса
   * @return integer - количество обработанных строк
   */
  public function query($sql) {

    $hRes = @mysql_query($sql, $this->hConn);
    if(! $hRes) {//Проверяем, корректно ливыполнен запрос
      $err = mysql_error($this->hConn) . $sql;
      throw new Exception($err);
    }

    return @mysql_affected_rows($this->hConn);
  }

  //Функция обновляет в таблице $table поля $arFieldValues, но только те элементы, которые соотвествуют условию $arConditions
  /**
   * Обновляет в таблице определенные поля, согласно условию
   *
   * @param string $table - название таблицы 
   * @param array $arFieldValues - массив обновляемых значений (ключ соответствует полю в БД)
   * @param array $arConditions - массив условий (ключ соответствует полю в БД)
   * @return integer - количество обновленных строк
   */
  public function update($table, $arFieldValues, $arConditions) {

    // Формируем корректный массив значений
    $arUpdates = array();//Массив элементов для значений
    foreach($arFieldValues as $field => $val) {//Проходим массив значений поэлементно
      if(! is_numeric($val)) { //Если текущее значение - не число
        $val = "'" . mysql_escape_string($val) . "'";//Приводим к корректному выводу
      }
      $arUpdates[] = "$field = $val";//Записываем корректное значение в массив
    }

    // Формируем корректный массив WHERE
    $arWhere = array();//Массив элементов для WHERE
    foreach($arConditions as $field => $val) {//Проходим массив WHERE поэлементно
      if(! is_numeric($val)) { //Если текущее значение - не число
        $val = "'" . mysql_escape_string($val) . "'";//Приводим к корректному выводу
      }
      $arWhere[] = "$field = $val";//Записываем корректное значение в массив
    }
    //Формируем SQL-запрос на обновление данных
    $sql  = "UPDATE $table SET ";
    $sql .= join(', ', $arUpdates);
    $sql .= ' WHERE ' . join(' AND ', $arWhere);
    $hRes = mysql_query($sql, $this->hConn);//Выполняем запрос
    if(! $hRes) {//Проверяем запрос на корректность
      $err = mysql_error($this->hConn) . $sql;
      throw new Exception($err);
    }

    return mysql_affected_rows($this->hConn);
  }

  /**
   * Деструктор - закрываем соединение с базой данных
   *
   */
  public function __destruct() {
    if(is_resource($this->hConn)) {
      @mysql_close($this->hConn);
    }
  }

  public function isRecordExist($sql) {
    $hRes = @mysql_query($sql, $this->hConn);

    if(! $hRes) {//Проверяем, корректно ливыполнен запрос
      $err = mysql_error($this->hConn) . $sql;
      throw new Exception($err);
    }
    if( mysql_num_rows($hRes) > 0 )
      return true;
    else
      return false;
  }
  
}
?>